package com.wing.tools.streamserver;

import android.media.MediaCodec;

import com.wing.tools.screenlive.encoder.VideoEncodeWorker;

import java.io.BufferedOutputStream;
import java.nio.ByteBuffer;

/**
 * Created by wejust on 2018/1/4.
 */

public class StreamServer implements VideoEncodeWorker.IReceiver{

    private String LOGTAG = StreamServer.class.getSimpleName();
    static {
        System.loadLibrary("zlmediakit");
    }

    boolean mRunning = false;
    long mediacontext;
    int mPort = 5554;
    String mAppName = "app";
    String mMediaName = "media";

    int mFrameInterval = 2;
    int mOutputWidth = 640,mOutputHeight = 480;
    int mVideoBitrate = 1 * 100 * 1000;
    int mFPS = 10;

    byte[] mBuffer = new byte[0];
    byte[] mConfig;
    long timer = -1;
    long startTime = 0;

    public BufferedOutputStream outputStream;

    public boolean getRunning(){
        return mRunning;
    }

    public void init(int port, String appName, String mediaName, int outWidth, int outHeight, int videoBitrate){
        this.mPort = port;
        this.mAppName = appName;
        this.mMediaName = mediaName;
        this.mOutputHeight = outHeight;
        this.mOutputWidth = outWidth;
        this.mVideoBitrate = videoBitrate;
    }

    public void start(){
        mRunning = true;

        ZLMediaKit.initRtspServer((short)mPort);
        mediacontext = ZLMediaKit.createMedia(this.mAppName, this.mMediaName);
        ZLMediaKit.mediaInitVideo(mediacontext, mOutputWidth, mOutputHeight, mVideoBitrate);
    }

    public void stop(){
        ZLMediaKit.releaseMedia(mediacontext);

        mRunning = false;
    }

    @Override
    public void onEncodedSample(MediaCodec.BufferInfo info, ByteBuffer data) {
        // Here we could have just used ByteBuffer, but in real life case we might need to
        // send sample over network, etc. This requires byte[]
        if (mBuffer.length < info.size) {
            mBuffer = new byte[info.size];
        }
        data.position(info.offset);
        data.limit(info.offset + info.size);
        data.get(mBuffer, 0, info.size);

        //Log.d("ENCODER_FLAG", String.valueOf(info.flags));

        if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == MediaCodec.BUFFER_FLAG_CODEC_CONFIG) {
            // this is the first and only config sample, which contains information about codec
            // like H.264, that let's configure the decoder

            mConfig = new byte[mBuffer.length];
            System.arraycopy(mBuffer, 0, mConfig, 0, mBuffer.length);

        } else {
            boolean iskey = (info.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) == MediaCodec.BUFFER_FLAG_KEY_FRAME;

            byte[] dt = mBuffer;
            if (timer < 0 || timer > mFrameInterval * 1000 || iskey) {
                int nalu_len = 0;
//                    if(mBuffer[0] == 0 && mBuffer[1] ==0 && mBuffer[2] == 0 && mBuffer[3] == 1){
//                        nalu_len = 5;
//                    }
                byte[] keyframe = new byte[mBuffer.length + mConfig.length - nalu_len];
                System.arraycopy(mConfig, 0, keyframe, 0, mConfig.length);
                System.arraycopy(mBuffer, nalu_len, keyframe, mConfig.length, mBuffer.length - nalu_len);

                dt = keyframe;

                timer = 0;
                startTime = System.nanoTime() / 1000000L;
            } else if ((info.flags & MediaCodec.BUFFER_FLAG_PARTIAL_FRAME) == MediaCodec.BUFFER_FLAG_PARTIAL_FRAME) {
                timer += (System.nanoTime() / 1000000L - startTime);
                //Log.d("dt__", "time:" + timer);
            }

            ZLMediaKit.mediaInputH264(mediacontext, dt, dt.length, System.nanoTime() / 1000000L, true);
        }
    }
}
